package com.netsdk.demo;

import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.enumeration.EM_EVENT_IVS_TYPE;
import com.netsdk.lib.enumeration.EM_EVENT_TYPE;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;

import static com.netsdk.lib.Utils.getOsPrefix;

/**
 * @author 291189
 * @version 1.0
 * @description 2022基线功能
 * 多设备登录，智能订阅 ，取消智能订阅；以及智能订阅dwUser的使用。
 * @date 2022/10/10 15:54
 */
public class BaseMoreLoginDemo {

  public static NetSDKLib netSdk = NetSDKLib.NETSDK_INSTANCE;

    static    List<Device> deviceList=new ArrayList<>();

   static {
        // 初始化SDK库
        netSdk.CLIENT_Init(DisconnectCallback.getInstance(), null);

        // 设置断线重连成功回调函数
        netSdk.CLIENT_SetAutoReconnect(HaveReconnectCallback.getInstance(), null);

        //打开日志，可选0
        NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO();
        String logPath = new File(".").getAbsoluteFile().getParent() + File.separator + "sdk_log" + File.separator + "sdk.log";
        setLog.bSetFilePath = 1;
        System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length);
        setLog.bSetPrintStrategy = 1;
        setLog.nPrintStrategy = 0;
        if (!netSdk.CLIENT_LogOpen(setLog)){
            System.err.println("Open SDK Log Failed!!!");
        }

    }
    /**
     * 设备断线回调
     */
    private static class DisconnectCallback implements NetSDKLib.fDisConnect {
        private static DisconnectCallback instance = new DisconnectCallback();

        private DisconnectCallback() {
        }

        public static DisconnectCallback getInstance() {
            return instance;
        }

        @Override
		public void invoke(NetSDKLib.LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("Device[%s:%d] Disconnect!\n", pchDVRIP, nDVRPort);
        }
    }
    /**
     * 设备重连回调
     */
    private static class HaveReconnectCallback implements NetSDKLib.fHaveReConnect {
        private static HaveReconnectCallback instance = new HaveReconnectCallback();

        private HaveReconnectCallback() {
        }

        public static HaveReconnectCallback getInstance() {
            return instance;
        }

        @Override
		public void invoke(NetSDKLib.LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser) {
            System.out.printf("Device[%s:%d] HaveReconnected!\n", pchDVRIP, nDVRPort);
        }
    }

    /**
     * 高安全登录
     */
    public   NetSDKLib.LLong loginWithHighLevel(String ip,int port,String user,String password) {
        // 输入结构体参数
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstlnParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY() {
            {
                szIP = ip.getBytes();
                nPort = port;
                szUserName = user.getBytes();
                szPassword = password.getBytes();
            }
        };

        // 输出结构体参数
        NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();

        // 写入sdk
        NetSDKLib.LLong loginHandle = netSdk.CLIENT_LoginWithHighLevelSecurity(pstlnParam, pstOutParam);
        if (loginHandle.longValue() == 0) {
            //  System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", ip, port, netSdk.CLIENT_GetLastError());
            System.out.println("Login Device[%s] Port[%d]Failed. "+ ip+":"+ port+":"+ netSdk.CLIENT_GetLastError());

        } else {
            NetSDKLib.NET_DEVICEINFO_Ex   deviceInfo = pstOutParam.stuDeviceInfo; // 获取设备信息
            System.out.println("Login Success");
            System.out.println("Device Address：" + ip);
            System.out.println("设备包含：" + deviceInfo.byChanNum + "个通道");
        }

        return loginHandle;
    }

    /**
     * 退出清理环境
     */
    public  void LoginOut(NetSDKLib.LLong lLong){
        System.out.println("End Test");
        if( lLong.longValue() != 0)
        {
            netSdk.CLIENT_Logout(lLong);
        }
        System.out.println("See You...");

    }
    public class  Device{
        public String ip;
        public int port;
        public NetSDKLib.LLong loginHandler=new NetSDKLib.LLong(0);//登录句柄
        public  List<DeviceHandler> deviceHandlers=new ArrayList<>();//订阅句柄

        public Device() {
        }

        @Override
        public String toString() {
            return "Device{" +
                    "ip='" + ip + '\'' +
                    ", port=" + port +
                    ", loginHandler=" + loginHandler.longValue()+
                    '}';
        }
    }


    public class DeviceHandler{
         public int channel;
         public NetSDKLib.LLong attachHandler=new NetSDKLib.LLong(0);//订阅句柄
         public String dwUser;

        @Override
        public String toString() {
            return "DeviceHandler{" +
                    "channel=" + channel +
                    ", attachHandler=" + attachHandler +
                    ", dwUser=" + dwUser +
                    '}';
        }
    }

    /**
     * 订阅智能任务
     */
    //存储dwuser,防止回收
    static HashMap<NetSDKLib.LLong,Pointer> pointers=new HashMap<>();

    public NetSDKLib.LLong AttachEventRealLoadPic(NetSDKLib.LLong loginHandle,NetSDKLib.LLong attachHandle,int channel,String dwUser) {
        // 先退订，设备不会对重复订阅作校验，重复订阅后会有重复的事件返回
        if(attachHandle.longValue()!=0){
            this.DetachEventRealLoadPic(attachHandle);
        }

        Pointer dwUserData = GetStringToPointer(dwUser,encode);

        // 需要图片
        int bNeedPicture = 1;
           attachHandle = netSdk.CLIENT_RealLoadPictureEx(loginHandle, channel, EM_EVENT_TYPE.EVENT_IVS_ALL.getType(), bNeedPicture,
                AnalyzerDataCB.getInstance(), dwUserData, null);
        if (attachHandle.longValue() != 0) {
            System.out.printf("Chn[%d] CLIENT_RealLoadPictureEx Success\n", channel);
            pointers.put(attachHandle,dwUserData);
        } else {
            System.out.printf("Chn[%d] CLIENT_RealLoadPictureEx Failed!LastError = %s\n", channel,
                    ToolKits.getErrorCode());

        }

        return attachHandle;
    }

    public static Pointer GetStringToPointer(String src,String charset) {
        Pointer pointer = null;
        try {
            byte[] b = src.getBytes(charset);

            pointer = new Memory(b.length + 1);
            pointer.clear(b.length + 1);

            pointer.write(0, b, 0, b.length);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return pointer;
    }

    public static String GetPointerDataToString(Pointer pointer,String charset) {
        String str = "";
        if (pointer == null) {
            return str;
        }

        int length = 0;
        byte[] bufferPlace = new byte[1];

        for (int i = 0; i < 2048; i++) {
            pointer.read(i, bufferPlace, 0, 1);
            if (bufferPlace[0] == '\0') {
                length = i;
                break;
            }
        }

        if (length > 0) {
            byte[] buffer = new byte[length];
            pointer.read(0, buffer, 0, length);
            try {
                str = new String(buffer, charset).trim();
            } catch (UnsupportedEncodingException e) {
                return str;
            }
        }

        return str;
    }

    /**
     * 报警事件（智能）回调
     */
    public  static class AnalyzerDataCB implements NetSDKLib.fAnalyzerDataCallBack {
        private final File picturePath;
        private static AnalyzerDataCB instance;

        private AnalyzerDataCB() {
            picturePath = new File("./AnalyzerPicture/");
            if (!picturePath.exists()) {
                picturePath.mkdirs();
            }
        }

        public static AnalyzerDataCB getInstance() {
            if (instance == null) {
                synchronized (AnalyzerDataCB.class) {
                    if (instance == null) {
                        instance = new AnalyzerDataCB();
                    }
                }
            }
            return instance;
        }


        @Override
        public int invoke(NetSDKLib.LLong lAnalyzerHandle, int dwAlarmType, Pointer pAlarmInfo, Pointer pBuffer, int dwBufSize,
                          Pointer dwUser, int nSequence, Pointer reserved) {
            if (lAnalyzerHandle == null || lAnalyzerHandle.longValue() == 0) {
                return -1;
            }

            String s = GetPointerDataToString(dwUser,encode);
            System.out.println("方法一 dwUser的值:"+s);
            for(int i=0;i<deviceList.size();i++){
                Device device = deviceList.get(i);

                List<DeviceHandler> deviceHandlers = device.deviceHandlers;
                for(DeviceHandler  deviceHandler:deviceHandlers){
                    if(deviceHandler.attachHandler.longValue()==lAnalyzerHandle.longValue()){
                        System.out.println("方法二 根据句柄关联:"+ "订阅句柄:"+deviceHandler.attachHandler+
                                ",设备信息:"+device.ip+":"+device.port+",通道号:"+deviceHandler.channel);
                    }
                }
            }

            switch (Objects.requireNonNull(EM_EVENT_IVS_TYPE.getEventType(dwAlarmType))) {
                case EVENT_IVS_FACEDETECT : {
                    System.out.println("人脸检测事件");
                    break;
                }
                //目标识别事件
                case EVENT_IVS_FACERECOGNITION:{

                    System.out.println("目标识别事件");

                    break;
                }
                case EVENT_IVS_NUMBERSTAT:{
                    System.out.println("数量统计事件");
                    break;
                }
                default:
                    System.out.println("其他事件--------------------"+ dwAlarmType);
                    break;
            }
            return 0;
        }
    }


    /**
     * 停止侦听智能事件
     */
    public void DetachEventRealLoadPic( NetSDKLib.LLong attachHandle) {
        if (attachHandle.longValue() != 0) {
            boolean b = netSdk.CLIENT_StopLoadPic(attachHandle);
            if(b){
                System.out.println("CLIENT_StopLoadPic success");
            }else {
                System.out.println("CLIENT_StopLoadPic fail!"+ToolKits.getErrorCode());

            }
        }
    }

   static Scanner scanner=new Scanner(System.in);

    public static void main(String[] args) {
       BaseMoreLoginDemo  baseMoreLoginDemo=new BaseMoreLoginDemo();

       baseMoreLoginDemo.runLogic();

    }


    public void runLogic(){

        while (true){
            System.out.println("0.退出");
            System.out.println("1.设备登录");
            System.out.println("2.选择设备 通道 智能订阅");
            System.out.println("3.选择设备 通道 取消订阅");
            //10.238.87.39,37777,admin,huichen123!@#
         for(int i=0;i<deviceList.size();i++){
             Device device = deviceList.get(i);
             System.out.println("设备下标："+i+":"+device.toString());

             List<DeviceHandler> deviceHandlers = device.deviceHandlers;

             for(int j=0;j<deviceHandlers.size();j++){
                 DeviceHandler deviceHandler = deviceHandlers.get(j);
                 System.out.println("订阅通道下标："+j+":"+deviceHandler.toString());
             }

         }
         try {
             int nextInt = scanner.nextInt();

             if(nextInt==0){
                 break;
             }else if(nextInt==1){
                 System.out.println("输入设备ip,端口,用户名,密码 逗号隔开;如：10.34.3.159,37777,admin,admin");
                 String next = scanner.next();
                 String[] split = next.split(",");
                 NetSDKLib.LLong lLong = loginWithHighLevel(split[0].trim(), Integer.parseInt(split[1].trim()), split[2], split[3]);
                 Device device=new Device();
                 device.ip=split[0].trim();
                 device.port=Integer.parseInt(split[1].trim());
                 device.loginHandler=lLong;
                 deviceList.add(device);
             }else if(nextInt==2){
                 System.out.println("选择设备下标和通道号进行订阅 逗号隔开 如 1,-1 ");

                 String next = scanner.next();

                 String[] split = next.split(",");

                 Device device = deviceList.get(Integer.parseInt(split[0].trim()));

                 int channl = Integer.parseInt(split[1].trim());

                 List<DeviceHandler> deviceHandlers = device.deviceHandlers;

                 NetSDKLib.LLong attachHandler=new NetSDKLib.LLong(0);

                 boolean flag=false;
                 int m=-1;
                 //轮询 设备的订阅通道
                 for( int i=0;i<deviceHandlers.size();i++){
                     DeviceHandler deviceHandler= deviceHandlers.get(i);

                     if(deviceHandler.channel==channl){
                         m=i;
                         attachHandler=deviceHandler.attachHandler;
                         flag=true;
                         break;
                     }
                 }
                 DeviceHandler deviceHandler=new DeviceHandler();

                 String  dwUser=  "设备信息:"+device.ip + ":" + device.port+": 通道号:"+channl;

                 deviceHandler.dwUser=dwUser;

                 deviceHandler.channel=channl;

                 attachHandler = AttachEventRealLoadPic(device.loginHandler, attachHandler,channl ,dwUser);

                 deviceHandler.attachHandler=attachHandler;

                 if(!flag){
                     deviceHandlers.add(deviceHandler);
                 }else {
                     deviceHandlers.remove(m);
                     deviceHandlers.add(deviceHandler);

                 }


             }else if(nextInt==3){
                 System.out.println("选择设备下标 和 订阅通道下标 进行取消订阅 逗号隔开 如 1,1 ");
                 String next = scanner.next();

                 String[] split = next.split(",");

                 Device device = deviceList.get(Integer.parseInt(split[0].trim()));

                 List<DeviceHandler> deviceHandlers = device.deviceHandlers;

                 DeviceHandler deviceHandler
                         = deviceHandlers.get(Integer.parseInt(split[1].trim()));

                 DetachEventRealLoadPic(deviceHandler.attachHandler);

                 pointers.remove(deviceHandler.attachHandler);

                 deviceHandlers.remove(Integer.parseInt(split[1].trim()));


             }else {
                 System.out.println("输入有误");
             }
         }catch (Exception e){
             e.printStackTrace();
         }



        }

        Iterator<Device> iterator = deviceList.iterator();

        while (iterator.hasNext()){
            Device next = iterator.next();
            if(next!=null&&next.loginHandler!=null&&next.loginHandler.longValue()!=0){
                LoginOut(next.loginHandler);
            }

        }

        netSdk.CLIENT_Cleanup();
    }
    // 编码格式
    public static String encode;

    static {
        String osPrefix = getOsPrefix();
        if (osPrefix.toLowerCase().startsWith("win32-amd64")) {
            encode = "GBK";
        } else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
            encode = "UTF-8";
        }

    }

}
